package com.bcdat.sso_user_management.config;

import io.buji.pac4j.filter.CallbackFilter;
import io.buji.pac4j.filter.LogoutFilter;
import io.buji.pac4j.filter.SecurityFilter;
import io.buji.pac4j.realm.Pac4jRealm;
import io.buji.pac4j.subject.Pac4jSubjectFactory;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.pac4j.cas.client.CasClient;
import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.cas.config.CasProtocol;
import org.pac4j.core.config.Config;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    @Bean
    @ConfigurationProperties(prefix = "cas")
    public CasProp casProp() {
        return new CasProp();
    }

    @Bean
    @ConfigurationProperties(prefix = "redis")
    public RedisProp redisProp() {
        return new RedisProp();
    }

    @Bean
    public FilterRegistrationBean shiroFilterBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //由容器管理生命周期
        filterRegistrationBean.addInitParameter("targetFilterLifecycle","true");
        filterRegistrationBean.setEnabled(true);
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        System.out.println(casProp());
        System.out.println(redisProp());



        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        LinkedHashMap<String, String> filterDefinitionMap = new LinkedHashMap<>();
//        filterDefinitionMap.put("/logout", "logout");
//        filterDefinitionMap.put("/cas/user/login", "anon");
//        filterDefinitionMap.put("/callback", "callbackFilter");
//        filterDefinitionMap.put("/**", "securityFilter");
        filterDefinitionMap.put("/**", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterDefinitionMap);
        shiroFilterFactoryBean.setLoginUrl(casProp().getLoginUrl());
        shiroFilterFactoryBean.setSuccessUrl(casProp().getSuccessUrl());
        shiroFilterFactoryBean.setUnauthorizedUrl(casProp().getUnauthorizedUrl());
        shiroFilterFactoryBean.setSecurityManager(securityManger());
        Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
        SecurityFilter securityFilter = new SecurityFilter();
        securityFilter.setConfig(config());
        securityFilter.setClients(casProp().getClientName());
        filters.put("securityFilter", securityFilter);
        CallbackFilter callbackFilter = new CallbackFilter();
        callbackFilter.setConfig(config());
        callbackFilter.setDefaultUrl(casProp().getServiceUrl());
        filters.put("callbackFilter", callbackFilter);
        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setConfig(config());
        logoutFilter.setCentralLogout(true);
        logoutFilter.setLocalLogout(true);
        logoutFilter.setDefaultUrl(casProp().getCallbackUrl());
        filters.put("logout", logoutFilter);
        shiroFilterFactoryBean.setFilters(filters);
        return shiroFilterFactoryBean;
    }


    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启注解声明:
     * 开启shiro aop 的注解支持，使用代理的方式，所以需要开启代码的支持
     * / 强制使用cglib，防止重复代理和可能引起代理出错的问题
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public Pac4jRealm pac4jRealm() {
        Pac4jRealm pac4jRealm = new Pac4jRealm();
        return pac4jRealm;
    }

    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisProp().getHost());
        return redisManager;
    }

    @Bean
    public DefaultWebSessionManager defaultWebSessionManager() {
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionDAO(redisSessionDAO());
        return defaultWebSessionManager;
    }
    @Bean
    public RedisCacheManager redisCacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }


    @Bean
    public DefaultWebSecurityManager securityManger() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(pac4jRealm());
        securityManager.setSessionManager(defaultWebSessionManager());
        securityManager.setSubjectFactory(pac4jSubjectFactory());
        return securityManager;
    }

    @Bean
    public Pac4jSubjectFactory pac4jSubjectFactory() {
        return new Pac4jSubjectFactory();
    }

    @Bean
    public Config config() {
        CasConfiguration casConfiguration = new CasConfiguration();
        casConfiguration.setLoginUrl(casProp().getLoginUrl());
        casConfiguration.setProtocol(CasProtocol.CAS20);
        casConfiguration.setAcceptAnyProxy(true);
        casConfiguration.setPrefixUrl(casProp().getCasServerUrl());
        CasClient casClient = new CasClient(casConfiguration);
        casClient.setCallbackUrl(casProp().getCallbackUrl());
        casClient.setName(casProp().getClientName());
        Config config = new Config(casClient);
        return config;
    }

    //开启权限注解
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManger());
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultHashService defaultHashService() {
        DefaultHashService defaultHashService = new DefaultHashService();
        defaultHashService.setHashAlgorithmName("MD5");
        defaultHashService.setHashIterations(10);
        defaultHashService.setPrivateSalt(ByteSource.Util.bytes("com.bcdat"));
        return defaultHashService;
    }
//    @Bean
//    public FilterRegistrationBean singleSignOutFilter() {
//        FilterRegistrationBean bean = new FilterRegistrationBean();
//        bean.setName("singleSignOutFilter");
//        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
//        singleSignOutFilter.setCasServerUrlPrefix(casProp().getCasServerUrl());
//        singleSignOutFilter.setIgnoreInitConfiguration(true);
//        bean.setFilter(singleSignOutFilter);
//        bean.addUrlPatterns("/*");
//        bean.setEnabled(true);
//        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
//        return bean;
//    }
}
